
import Foundation

#if canImport(UIKit)
import UIKit
#endif

public struct LsqDecoder {
    //TODO:转换模型(单个)
    public static func decode<T>(_ type: T.Type, param: [String:Any]) -> T? where T: Decodable {
        return type.decode(param)
    }
    //多个
    public static func decode<T>(_ type: T.Type, array: [[String:Any]]) -> [T]? where T: Decodable {
        if let data = self.getJsonData(with: array) {
            do {
                let models = try JSONDecoder().decode([T].self, from: data)
                return models
            } catch {
                print("转换模型(多个)==>解析异常--\(error)")
                return nil
            }
        } else {
            print("模型转换->转换data失败")
        }
        return nil
    }
    private static func getJsonData(with param: Any) -> Data? {
        if !JSONSerialization.isValidJSONObject(param) {
            return nil
        }
        guard let data = try? JSONSerialization.data(withJSONObject: param, options: []) else {
            return nil
        }
        return data
    }
}
//模型转字典，或转json字符串
struct LsqEncoder {
    ///转换为字符串
    public static func encoder<T>(toString model: T) -> String? where T: Encodable {
        
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        guard let data = try? encoder.encode(model) else {
            return nil
        }
        guard let jsonStr = String(data: data, encoding: .utf8) else {
            return nil
        }
        return jsonStr
    }
    ///转换为字典
    public static func encoder<T>(toDictionary model: T) -> [String:Any]? where T: Encodable {
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        guard let data = try? encoder.encode(model) else {
            return nil
        }
        guard let dict = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [String:Any] else {
            return nil
        }
        return dict
    }
}
//TODO:模型归档
extension Encodable {
    ///转换为Data
    public func encoder() -> Data? {
        let ecd = JSONEncoder()
        ecd.outputFormatting = .prettyPrinted
        return try? ecd.encode(self)
    }
    
    //以下为快捷方式
    ///转换为String
    public func toString() -> String? {
        return self.encoder()?.toString()
    }
    ///转换为Dictionary
    public func toDictionary() -> [String:Any]? {
        return self.encoder()?.toDictionary()
    }
    ///转换为Array
    public func toArrray() -> [Any]? {
        return self.encoder()?.toArrray()
    }
}
extension Data {
    ///Data->Dictionary
    public func toDictionary() -> [String:Any]? {
        return try? JSONSerialization.jsonObject(with: self, options: .mutableLeaves) as? [String:Any]
    }
    ///Data->String
    public func toString() -> String? {
        return String(data: self, encoding: .utf8)
    }
    ///Data->Array
    public func toArrray() -> [Any]? {
        return try? JSONSerialization.jsonObject(with: self, options: .mutableLeaves) as? [Any]
    }
}

//TODO:模型解析
extension Decodable {
    ///dictionary->模型 temp:  Model.decode(dic)
    public static func decode(_ dictionary: [String:Any]) -> Self? {
        guard let data = self.getJsonData(with: dictionary) else {
            print("转换date失败")
            return nil
        }
        do {
            let model = try JSONDecoder().decode(Self.self, from: data)
            return model
        } catch {
            print(error)
            return nil
        }
    }
    ///array->模型 temp: [Model].decode(array)
    public static func decode(_ array: [[String:Any]]) -> Self? {
        guard let data = self.getJsonData(with: array) else {
            print("转换date失败")
            return nil
        }
        do {
            let model = try JSONDecoder().decode(Self.self, from: data)
            return model
        } catch {
            print(error)
            return nil
        }
    }
    
    private static func getJsonData(with param: Any) -> Data? {
        if !JSONSerialization.isValidJSONObject(param) {
            return nil
        }
        guard let data = try? JSONSerialization.data(withJSONObject: param, options: []) else {
            return nil
        }
        return data
    }
}



public protocol LsqCodable: Codable {
    associatedtype T: Codable
    var wrappedValue: T? { get set }
    
    init(wrappedValue: T?)
}

///注意 String、 Int 和 Double 都转换成String, 返回数据类型不明确时使用
@propertyWrapper
public struct LsqStringable: LsqCodable, Codable {
    
    public var wrappedValue: String?
    public init(wrappedValue: String? = nil) {
        self.wrappedValue = wrappedValue
    }
    public init(from decoder: Decoder) throws {
        do {
            let container = try decoder.singleValueContainer()
            if container.decodeNil() {
                return
            }
            if let value = try? container.decode(String.self) {
                wrappedValue = value
            } else if let value = try? container.decode(Int.self) {
                wrappedValue = "\(value)"
            } else {
                do {
                    let value = try container.decode(Double.self)
                    wrappedValue = "\(value)"
                } catch {
                    print("<====【解析异常】===>我不是String、Int、也不是Double==>\(error)")
                }
            }
        } catch {
            print("<=x===【LsqStringable解析异常】==x=>\(error)")
        }
        
    }
}


///注意 Int、String  都转换成Int, 返回数据类型不明确时使用
@propertyWrapper
public struct LsqIntable: LsqCodable {
    
    public var wrappedValue: Int?
    public init(wrappedValue: Int? = nil) {
        self.wrappedValue = wrappedValue
    }
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if container.decodeNil() {
            return
        }
        if let value = try? container.decode(Int.self) {
            wrappedValue = value
        } else {
            do {
                let value = try container.decode(String.self)
                if let intValue = Int(value) {
                    wrappedValue = intValue
                } else {
                    print("<====【解析异常】===>LsqIntable不能将String转换为Int***\(container.codingPath)")
                }
            } catch {
                print("<====【解析异常】===>我不是Int、也不是String==>\(error)")
            }
        }
    }
}
///注意 Bool、String  都转换成Bool, 返回数据类型不明确时使用
@propertyWrapper
public struct LsqBoolable: LsqCodable {
    
    public var wrappedValue: Bool?
    public init(wrappedValue: Bool? = nil) {
        self.wrappedValue = wrappedValue
    }
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if container.decodeNil() {
            return
        }
        if let value = try? container.decode(Bool.self) {
            wrappedValue = value
        } else {
            do {
                let value = try container.decode(String.self)
                if let boolValue = Bool(value) {
                    wrappedValue = boolValue
                } else {
                    print("<====【解析异常】===>LsqBoolable不能将String转换为Bool***\(container.codingPath)")
                }
            } catch {
                print("<====【解析异常】===>我不是Bool、也不是String==>\(error)")
            }
        }
    }
}
///注意 Double、String  都转换成Double, 返回数据类型不明确时使用
@propertyWrapper
public struct LsqDoubleable: LsqCodable {
    
    public var wrappedValue: Double?
    public init(wrappedValue: Double? = nil) {
        self.wrappedValue = wrappedValue
    }
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if container.decodeNil() {
            return
        }
        if let value = try? container.decode(Double.self) {
            wrappedValue = value
        } else {
            do {
                let value = try container.decode(String.self)
                if let doubleValue = Double(value) {
                    wrappedValue = doubleValue
                } else {
                    print("<====【解析异常】===>LsqDoubleable不能将String转换为Double***\(container.codingPath)")
                }
            } catch {
                print("<====【解析异常】===>我不是Double、也不是String==>\(error)")
            }
        }
    }
}

// MARK: 如果key不存在，则返回空
extension KeyedDecodingContainer {
    
    func decode<T: LsqCodable>(_ type: T.Type, forKey key: Key) throws -> T {
        do {
            if !self.contains(key) {
                print("LsqCodable.decode的Key=>[\(key.stringValue)]不存在,keyType=>\(type)\n")
                return T.init(wrappedValue: nil)
            }
            if let value = try decodeIfPresent(type, forKey: key) {
                return value
            } else {
                return T.init(wrappedValue: nil)
            }
        } catch {
            print("[LsqCodable.decode]==>\(error)")
            return T.init(wrappedValue: nil)
        }
    }
}

extension KeyedEncodingContainer {
    mutating func encode(_ value: some LsqCodable, forKey key: Self.Key) throws {
        try encodeIfPresent(value.wrappedValue, forKey: key)
    }
}
